package com.opennetexam.manager.utils.lock.impl;

import com.opennetexam.manager.utils.lock.AcquiredLockWorker;
import com.opennetexam.manager.utils.lock.DistributedLocker;
import com.opennetexam.manager.utils.lock.RedissonConnector;
import com.opennetexam.manager.utils.lock.UnableToAquireLockException;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @Description TODO
 * @Author 奶茶
 * Created by on 2019/2/20 9:57.
 */
@Component
public class RedisLocker implements DistributedLocker{

    private static final Logger logger = LoggerFactory.getLogger(RedisLocker.class);

    private final static String LOCKER_PREFIX = "LOCK:";

    @Autowired
    private RedissonConnector connector;

    /**
     *
     * @param lockName 锁名称
     * @param leaseTime 租约时间
     * @param waitTime 获取锁等待时间
     * @param worker 获取锁后的处理类
     * @param <T>
     * @return
     * @throws UnableToAquireLockException
     * @throws InterruptedException
     */
    @Override
    public <T> T lock(String lockName,int leaseTime,int waitTime, AcquiredLockWorker<T> worker) throws UnableToAquireLockException, InterruptedException {
        return lock(lockName,worker,leaseTime,waitTime);
    }

    @Override
    public <T> T lock(String lockName, AcquiredLockWorker<T> worker, int leaseTime,int waitTime) throws UnableToAquireLockException, InterruptedException {
        RedissonClient redissonClient = connector.getRedissonClient();
        RLock lock = redissonClient.getLock(LOCKER_PREFIX + lockName);
        boolean success = lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        logger.info("获取锁：" + success);
        if(success){
            try {
                return worker.invokeAfterLockAcquired();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
              lock.unlock();
            }
        }
        return null;
    }
}
